
#include "rtthread.h"
#include "rthw.h"

extern rt_list_t rt_thread_priority_table[RT_THREAD_PRIORITY_MAX];

extern struct rt_thread *rt_current_thread; /* 当前线程结构体指针	*/

extern rt_uint32_t rt_thread_ready_priority_group;

void rt_thread_timeout(void *parameter);

/**
* 线程初始化
*
* @param thread 待初始化的线程指针
* @param name   给线程起的名称
* @param entry  线程实际入口函数
* @param parameter    初始给的参数
* @param stack_start  线程堆栈起始地址，栈顶地址
* @param stack_size   堆栈大小
* @param priority   	线程优先级
*	@param tick   			同优先级线程时间片轮转用的时间
* @return 操作状态, RT_EOK on OK, -RT_ERROR on error
*/
rt_err_t rt_thread_init(struct rt_thread *thread, 
												 const char *name,
												 void (*entry)(void *parameter), 
												 void *parameter, 
												 void *stack_start, 
												 rt_uint32_t stack_size,
												 rt_uint8_t priority,
												 rt_uint32_t tick) 
 {
		/* 线程对象初始化 */
		/* 线程结构体开头部分的 4 个成员就是 rt_object_t 成员 ,相当于 rt_thread 继承了 rt_object_t */
		rt_object_init((rt_object_t)thread, RT_Object_Class_Thread, name);
		
	  /* 初始化线程链表内容，指向自己，使用线程优先级时使用，将线程结构体挂到某个优先级链表上 */
		rt_list_init(&(thread->tlist)); 

		thread->entry = (void *)entry; 
		thread->parameter = parameter; 

		thread->stack_addr = stack_start; 
		thread->stack_size = stack_size; 

		/* 初始化线程栈，并返回线程栈指针 */ 
		/* 
			stack_addr = 0x20000058;
			stack_size = 0x200;= 512;
			传参 stack_addr = 0x20000058 + 0x200 - 4 = 0x20000254;
		*/
		thread->sp = (void *)rt_hw_stack_init( thread->entry, thread->parameter, (void *)((char *)thread->stack_addr + thread->stack_size - 4), RT_NULL );
		
		/* 优先级初始化 */
		thread->init_priority = priority;
		thread->current_priority = priority;
		thread->number_mask = 0;
		
		/* 错误码和状态 */
		thread->error = RT_EOK;
		thread->stat = RT_THREAD_INIT;

		/* 时间片相关 */
		thread->init_tick = tick;
		thread->remaining_tick = tick;
	
		/* 初始化线程定时器 */
		rt_timer_init(&(thread->thread_timer), /* 静态定时器对象 */
									thread->name, /* 定时器的名字，直接使用的是线程的名字 */
									rt_thread_timeout, /* 超时函数 */
									thread, /* 超时函数形参 */
									0, /* 延时时间 */
									RT_TIMER_FLAG_ONE_SHOT); /* 定时器的标志 */
		
		return RT_EOK; 
}


/**
* 启动一个线程并将其放到系统的就绪列表中
*
* @param thread 待启动的线程
*
* @return 操作状态, RT_EOK on OK, -RT_ERROR on error
*/
rt_err_t rt_thread_startup(rt_thread_t thread)
{
		/* 设置当前优先级为初始优先级 */
		thread->current_priority = thread->init_priority;
		thread->number_mask = 1L << thread->current_priority;

		/* 改变线程的状态为挂起状态 */
		thread->stat = RT_THREAD_SUSPEND;
		/* 然后恢复线程 */
		rt_thread_resume(thread);

		if (rt_thread_self() != RT_NULL)
		{
				/* 系统调度 暂 时 不 会 执 行 ， 因 为 系 统 还 没 有 启 动 ，rt_current_thread 的值还是 RT_NULL*/
				rt_schedule();
		}

		return RT_EOK;
}


/**
* 该函数用于恢复一个线程然后将其放到就绪列表
*
* @param thread 需要被恢复的线程
*
* @return 操作状态, RT_EOK on OK, -RT_ERROR on error
*/
rt_err_t rt_thread_resume(rt_thread_t thread)
{
		register rt_base_t temp;
		/* 将被恢复的线程必须在挂起态，否则返回错误码 */
		if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_SUSPEND)
		{
				return -RT_ERROR;
		}
		/* 关中断 */
		temp = rt_hw_interrupt_disable();

		/* 从挂起队列移除 */
		rt_list_remove(&(thread->tlist));

		/* 开中断 */
		rt_hw_interrupt_enable(temp);

		/* 插入就绪列表 */
		rt_schedule_insert_thread(thread);

		return RT_EOK;
}

/* 获取当前正在运行的线程控制块指针 */
rt_thread_t rt_thread_self(void)
{
		return rt_current_thread;
}

/**
* 该函数用于挂起指定的线程
* @param thread 要被挂起的线程
*
* @return 操作状态, RT_EOK on OK, -RT_ERROR on error
*
* @note 如果挂起的是线程自身，在调用该函数后，
* 必须调用 rt_schedule()进行系统调度
*
*/
rt_err_t rt_thread_suspend(rt_thread_t thread)
{
		register rt_base_t temp;
	
		/* 只有就绪的线程才能被挂起，否则退出返回错误码 */ 
		if ((thread->stat & RT_THREAD_STAT_MASK) != RT_THREAD_READY)
		{
				return -RT_ERROR;
		}
		/* 关中断 */
		temp = rt_hw_interrupt_disable();
		/* 改变线程状态 */
		thread->stat = RT_THREAD_SUSPEND;
		/* 将线程从就绪列表删除 */
		rt_schedule_remove_thread(thread);
		/* 停止线程定时器 */
		rt_timer_stop(&(thread->thread_timer));
		/* 开中断 */
		rt_hw_interrupt_enable(temp);
		return RT_EOK;
}

/**
* 该函数将让当前线程睡眠一段时间，单位为 tick
*
* @param tick 睡眠时间，单位为 tick
*
* @return RT_EOK
*/
rt_err_t rt_thread_sleep(rt_tick_t tick)
{
		register rt_base_t temp;
		struct rt_thread *thread;
	
		/* 关中断 */
		temp = rt_hw_interrupt_disable();
		/* 获取当前线程的线程控制块 */
		thread = rt_current_thread;
		/* 挂起线程 */
		rt_thread_suspend(thread);
		/* 设置线程定时器的超时时间 */
		rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &tick);
		/* 启动定时器 */
		rt_timer_start(&(thread->thread_timer));
		/* 开中断 */
		rt_hw_interrupt_enable(temp);
	
		/* 执行系统调度 */
		rt_schedule();
		
		return RT_EOK;
}

/* 
*	线程阻塞延时函数
*	阻塞延时的阻塞是指线程调用该延时函数后，线程会被剥离 CPU 使用权，然后进入阻塞状态，直到延时结束，
* 线程重新获取 CPU 使用权才可以继续运行。在线程阻塞的这段时间， CPU 可以去执行其它的线程，
* 如果其它的线程也在延时状态，那么 CPU 就将运行空闲线程。
*/
#if 0
void rt_thread_delay(rt_tick_t tick)
{
#if 0
		struct rt_thread *thread;
		/* 获取当前线程的线程控制块 */
		thread = rt_current_thread;
		/* 设置延时时间 */
		thread->remaining_tick = tick;
		/* 进行系统调度 */
		rt_schedule();
#else
		register rt_base_t temp;
		struct rt_thread *thread;
		
		/* 失能中断 */
		temp = rt_hw_interrupt_disable();
		
		thread = rt_current_thread;
		thread->remaining_tick = tick;
		
		/* 改变线程状态 */
		thread->stat = RT_THREAD_SUSPEND;
		/* 清0线程就绪优先级组相应bit */
		rt_thread_ready_priority_group &= ~thread->number_mask;
		
		/* 使能中断 */
		rt_hw_interrupt_enable(temp);
		
		/* 进行系统调度 */
		rt_schedule();
#endif
}
#else
rt_err_t rt_thread_delay(rt_tick_t tick)
{
		return rt_thread_sleep(tick);
}
#endif

/**
* 线程超时函数
* 当线程延时到期或者等待的资源可用或者超时时，该函数会被调用
*
* @param parameter 超时函数的形参
*/
void rt_thread_timeout(void *parameter)
{
		struct rt_thread *thread;
		
		thread = (struct rt_thread *)parameter;
		/* 设置错误码为超时 */
		thread->error = -RT_ETIMEOUT;
		/* 将线程从挂起列表中删除 前提是线程在等待某些资源而被挂起到挂起列表，如果只是延时到期，则这个只是空操作。*/
		rt_list_remove(&(thread->tlist));
		/* 将线程插入到就绪列表 */
		rt_schedule_insert_thread(thread);
		/* 系统调度 */
		rt_schedule();
}

/**
*	rt_err_t rt_thread_yield(void)
* 该函数将让当前线程让出处理器，调度器选择最高优先级的线程运行。当前让出处理器之后，当前线程还是在就绪态。
* 
*
* @return RT_EOK
*/
rt_err_t rt_thread_yield(void)
{
		register rt_base_t level;
		struct rt_thread *thread;
	
		/* 关中断 */
		level = rt_hw_interrupt_disable();
		
		/* 获取当前线程的线程控制块 */
		thread = rt_current_thread;
		/* 如果线程在就绪态，且同一个优先级下不止一个线程 */
		if ((thread->stat & RT_THREAD_STAT_MASK) == RT_THREAD_READY && thread->tlist.next != thread->tlist.prev)
		{
				/* 将时间片耗完的线程从就绪列表移除 */
				rt_list_remove(&(thread->tlist));
				/* 将线程插入到该优先级下的链表的尾部 */
				rt_list_insert_before(&(rt_thread_priority_table[thread->current_priority]), &(thread->tlist));
				/* 开中断 */
				rt_hw_interrupt_enable(level);
				/* 执行调度 */
				rt_schedule();
				return RT_EOK;
		}
		
		/* 开中断 */
		rt_hw_interrupt_enable(level);
		return RT_EOK;
}

